/*
 * Matthew Cramer, Jesse Martinez, Marc Mendoza 
 * CSE 325 Lab 5
 * File: Tests.c
 * Description: Program to test the Memory Manager.  Reports tests that
 *              are being done and if they passed or *FAILED*.  
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../QueueManager/QueueManager.h"
#include "../MemoryManager/MemoryManager.h"
#include "../LRU/LRU.h"
#define MAX_PT 16
#define MAX_PT_SIZE 1024

int main(int argc, char *argv[])
{
    int temp=0;
    char text1[500], text2[500];
    FILE *file1;
    FILE *file2;
    printf("\nTests for Lab 5 - Memory Manager\n");
    
/*********************************************
 Functionality Tests
 ********************************************/    
    printf("\n****Functionality Tests****\n");
    printf("These tests are conducted by comparing a sample\n");
    printf("output with the output of a file generated from\n");
    printf("running through the program.  These the output of\n");
    printf("the program checks the functionality of the functions\n");
    printf("and ensures that each output is correct.  If both\n");
    printf("of the files are the same, then the test PASSED.\n");
    printf("If both test files were not the same, then in FAILED.\n");
    printf("For a description of each test, see the documentation.\n");

	/*********************************************
     init mem Arguments
     Ensures that the init mem function has the 
     correct argument for the function
     ********************************************/
    printf("\n**init_mem Arguments**\n");
    temp=0;
    file1 = fopen("./Tests/Test_init_mem_ARG.txt","r");
    file2 = fopen("./Tests/Test_init_mem_ARG_OUTPUT.txt","r");
    if(file1 != NULL && file2 != NULL)
    {
        fgets(text1,500,file1);
        fgets(text2,500,file2);
        while((fgets(text1,500,file1) != NULL && fgets(text2,500,file2) != NULL) && temp != 1)
        {
            if(strcmp(text1, text2) != 0)
                temp = 1;
        }
        fclose(file1);
        fclose(file2);
    }
    else
        temp = 1;
    if(temp==0)
        printf("init mem Arguments: PASSED\n");
    else
        printf("init mem Arguments: *FAILED*\n");

    /*********************************************
     init mem
     Ensures that the init mem function is called
     at the start of the program 
     ********************************************/
    printf("\n**init mem**\n");
    temp=0;
    file1 = fopen("./Tests/Test_init_mem.txt","r");
    file2 = fopen("./Tests/Test_init_mem_OUTPUT.txt","r");
    if(file1 != NULL && file2 != NULL)
    {
        fgets(text1,500,file1);
        fgets(text2,500,file2);
        while((fgets(text1,500,file1) != NULL && fgets(text2,500,file2) != NULL) && temp != 1)
        {
            if(strcmp(text1, text2) != 0)
                temp = 1;
        }
        fclose(file1);
        fclose(file2);
    }
    else
        temp = 1;
    if(temp==0)
        printf("init mem: PASSED\n");
    else
        printf("init mem: *FAILED*\n");
    
    /*********************************************
     List Arguments
     Ensures that List displays the correct output
     for the different arguments
     ********************************************/
    printf("\n**List Arguments**\n");
    temp=0;
    file1 = fopen("./Tests/Test_List_ARG.txt","r");
    file2 = fopen("./Tests/Test_List_ARG_OUTPUT.txt","r");
    if(file1 != NULL && file2 != NULL)
    {
        fgets(text1,500,file1);
        fgets(text2,500,file2);
        while((fgets(text1,500,file1) != NULL && fgets(text2,500,file2) != NULL) && temp != 1)
        {
            if(strcmp(text1, text2) != 0)
                temp = 1;
        }
        fclose(file1);
        fclose(file2);
    }
    else
        temp = 1;
    if(temp==0)
        printf("List Arguments: PASSED\n");
    else
        printf("List Arguments: *FAILED*\n");
    
    /*********************************************
     List
     Ensures that List displays the correct output
     when called
     ********************************************/
    printf("\n**List**\n");
    temp=0;
    file1 = fopen("./Tests/Test_List.txt","r");
    file2 = fopen("./Tests/Test_List_OUTPUT.txt","r");
    if(file1 != NULL && file2 != NULL)
    {
        fgets(text1,500,file1);
        fgets(text2,500,file2);
        while((fgets(text1,500,file1) != NULL && fgets(text2,500,file2) != NULL) && temp != 1)
        {
            if(strcmp(text1, text2) != 0)
                temp = 1;
        }
        fclose(file1);
        fclose(file2);
    }
    else
        temp = 1;
    if(temp==0)
        printf("List: PASSED\n");
    else
        printf("List: *FAILED*\n");

	/*********************************************
    alloc_pt arguments
    Ensures that alloc_pt takes in the correct 
    number of arguments and errors if not
    ********************************************/
    printf("\n**alloc_pt Arguments**\n");
    temp=0;
    file1 = fopen("./Tests/Test_alloc_pt_ARG.txt","r");
    file2 = fopen("./Tests/Test_alloc_pt_ARG_OUTPUT.txt","r");
    if(file1 != NULL && file2 != NULL)
    {
        fgets(text1,500,file1);
        fgets(text2,500,file2);
        while((fgets(text1,500,file1) != NULL && fgets(text2,500,file2) != NULL) && temp != 1)
        {
            if(strcmp(text1, text2) != 0)
                temp = 1;
        }
        fclose(file1);
        fclose(file2);
    }
    else
        temp = 1;
    if(temp==0)
        printf("alloc_pt Arguments: PASSED\n");
    else
        printf("alloc_pt Arguments: *FAILED*\n");
    
    /*********************************************
     alloc_pt
     Ensures that alloc_pt displays the correct 
     output for the command.  The list function
     will be used to determine if alloc_pt is working
     ********************************************/
    printf("\n**alloc_pt**\n");
    temp=0;
    file1 = fopen("./Tests/Test_alloc_pt.txt","r");
    file2 = fopen("./Tests/Test_alloc_pt_OUTPUT.txt","r");
    if(file1 != NULL && file2 != NULL)
    {
        fgets(text1,500,file1);
        fgets(text2,500,file2);
        while((fgets(text1,500,file1) != NULL && fgets(text2,500,file2) != NULL) && temp != 1)
        {
            if(strcmp(text1, text2) != 0)
                temp = 1;
        }
        fclose(file1);
        fclose(file2);
    }
    else
        temp = 1;
    if(temp==0)
        printf("alloc_pt: PASSED\n");
    else
        printf("alloc_pt: *FAILED*\n");
    
	/*********************************************
    dealloc_pt Arguments
    Ensures that the correct arguments are used
    for this function and errors if not
    ********************************************/
    printf("\n**dealloc_pt Arguments**\n");
    temp=0;
    file1 = fopen("./Tests/Test_dealloc_pt_ARG.txt","r");
    file2 = fopen("./Tests/Test_dealloc_pt_ARG_OUTPUT.txt","r");
    if(file1 != NULL && file2 != NULL)
    {
        fgets(text1,500,file1);
        fgets(text2,500,file2);
        while((fgets(text1,500,file1) != NULL && fgets(text2,500,file2) != NULL) && temp != 1)
        {
            if(strcmp(text1, text2) != 0)
                temp = 1;
        }
        fclose(file1);
        fclose(file2);
    }
    else
        temp = 1;
    if(temp==0)
        printf("dealloc_pt Arguments: PASSED\n");
    else
        printf("dealloc_pt Arguments: *FAILED*\n");

    /*********************************************
     dealloc_pt
     Ensures that dealloc_pt removes the correct
     page table from memory and deallocates all
     the memory used by that process
     ********************************************/
    printf("\n**dealloc_pt**\n");
    temp=0;
    file1 = fopen("./Tests/Test_dealloc_pt.txt","r");
    file2 = fopen("./Tests/Test_dealloc_pt_OUTPUT.txt","r");
    if(file1 != NULL && file2 != NULL)
    {
        fgets(text1,500,file1);
        fgets(text2,500,file2);
        while((fgets(text1,500,file1) != NULL && fgets(text2,500,file2) != NULL) && temp != 1)
        {
            if(strcmp(text1, text2) != 0)
                temp = 1;
        }
        fclose(file1);
        fclose(file2);
    }
    else
        temp = 1;
    if(temp==0)
        printf("dealloc_pt: PASSED\n");
    else
        printf("dealloc_pt: *FAILED*\n");

	/*********************************************
    page_fault Arguments
    Ensures that page_fault takes in the correct
    arguments and errors if not
    ********************************************/
    printf("\n**page_fault Arguments**\n");
    temp=0;
    file1 = fopen("./Tests/Test_page_fault_ARG.txt","r");
    file2 = fopen("./Tests/Test_page_fault_ARG_OUTPUT.txt","r");
    if(file1 != NULL && file2 != NULL)
    {
        fgets(text1,500,file1);
        fgets(text2,500,file2);
        while((fgets(text1,500,file1) != NULL && fgets(text2,500,file2) != NULL) && temp != 1)
        {
            if(strcmp(text1, text2) != 0)
                temp = 1;
        }
        fclose(file1);
        fclose(file2);
    }
    else
        temp = 1;
    if(temp==0)
        printf("page_fault Arguments: PASSED\n");
    else
        printf("page_fault Arguments: *FAILED*\n");

    /*********************************************
     page_fault
     Ensures that when a page fault is called that
     it brings a frame into memory if there is room.
     If not, it will call the LRU function to figure
     out which frame to switch out.  List functions 
     will be used to ensure that each page is placed
     in Physical Memory and Backing Store
     ********************************************/
    printf("\n**page_fault**\n");
    temp=0;
    file1 = fopen("./Tests/Test_page_fault.txt","r");
    file2 = fopen("./Tests/Test_page_fault_OUTPUT.txt","r");
    if(file1 != NULL && file2 != NULL)
    {
        fgets(text1,500,file1);
        fgets(text2,500,file2);
        while((fgets(text1,500,file1) != NULL && fgets(text2,500,file2) != NULL) && temp != 1)
        {
            if(strcmp(text1, text2) != 0)
                temp = 1;
        }
        fclose(file1);
        fclose(file2);
    }
    else
        temp = 1;
    if(temp==0)
        printf("page_fault: PASSED\n");
    else
        printf("page_fault: *FAILED*\n");
 
    
/*********************************************
 Capacitiy Tests
********************************************/    
    
    printf("\n****Capacitiy Tests****\n");
   
    /*********************************************
     Empty Arrays for Memory
     Ensures that all queues are initialized correctly
	 Ensures that the first index of Physical Memory
	 is allocated for the heads of the page tables
	 when created
     ********************************************/  
    printf("**Empty Queues**\n");

    //Initiate All Queues for testing
	clearMemory();

	if(getHead(1) == 0 && getTail(1) == 0 && getFreeHead(1) == 1 && getFreeTail(1) == 256-1)
		printf("Physical Memory Initiated: PASSED\n");
	else
		printf("Physical Memory Initiated: *FAILED*\n");
	if(getHead(2) == -1 && getTail(2) == -1 && getFreeHead(2) == 0 && getFreeTail(2) == 16384-1)
		printf("Backing Store Initiated: PASSED\n");
	else
		printf("Backing Store Initiated: *FAILED*\n");
	memory_block *phymem = getLogicalMemory();
	int i;
    temp=0;
	for(i=0; i<MAX_PT; i++)
	{
		if(phymem[0].pagetable[i].valid == 0)
			temp++;
	}
	if(temp==MAX_PT)
		printf("Page Table Header Array: PASSED\n");
	else
		printf("Page Table Header Array: *FAILED*\n");



    /*********************************************
     Max Queues
     Ensures that all queues can be filled to capacity
     with page tables and all the memory allocated for them.
     This includes Physical Memory and Backing Store
     ********************************************/    
    printf("\n**Max Queues**\n");
    
    alloc_pt(MAX_PT_SIZE,1);
    for(i=0;i<MAX_PT_SIZE; i++)
        page_fault(0,i);

    int sizePM = getSize(1);
    int sizeBS = getSize(2);
    temp=0;

    if(sizePM == 256)
        temp++;
    if(sizePM > 0)
        temp++;
    if(temp == 2)
        printf("Max of Physical Memory/Overflow into Backing Store: PASSED\n");
    else
        printf("Max of Physical Memory/Overflow into Backing Store: *FAILED*\n");
    
    
    /*********************************************
     Max Queues/Clear Some Page Tables
     Ensures that the queues can be filled to capacity
     with page tables and and then delete some page tables
     ********************************************/
    printf("\n**Max Queues/Deallocate Some**\n");
    
    clearMemory();
   
    alloc_pt(MAX_PT_SIZE,1);
    for(i=0;i<MAX_PT_SIZE; i++)
        page_fault(0,i);
    alloc_pt(MAX_PT_SIZE,1);
    for(i=0;i<MAX_PT_SIZE; i++)
        page_fault(1,i);
    alloc_pt(MAX_PT_SIZE,1);
    for(i=0;i<MAX_PT_SIZE; i++)
        page_fault(2,i);
    alloc_pt(MAX_PT_SIZE,1);
    for(i=0;i<MAX_PT_SIZE; i++)
        page_fault(3,i);
    alloc_pt(MAX_PT_SIZE,1);
    for(i=0;i<MAX_PT_SIZE; i++)
        page_fault(4,i);
    alloc_pt(MAX_PT_SIZE,1);
    for(i=0;i<MAX_PT_SIZE; i++)
        page_fault(5,i);
    alloc_pt(MAX_PT_SIZE,1);
    for(i=0;i<MAX_PT_SIZE; i++)
        page_fault(6,i);
    alloc_pt(MAX_PT_SIZE,1);
    for(i=0;i<MAX_PT_SIZE; i++)
        page_fault(7,i);
    alloc_pt(MAX_PT_SIZE,1);
    for(i=0;i<MAX_PT_SIZE; i++)
        page_fault(8,i);
    alloc_pt(MAX_PT_SIZE,1);
    for(i=0;i<MAX_PT_SIZE; i++)
        page_fault(9,i);
    alloc_pt(MAX_PT_SIZE,1);
    for(i=0;i<MAX_PT_SIZE; i++)
        page_fault(10,i);
    alloc_pt(MAX_PT_SIZE,1);
    for(i=0;i<MAX_PT_SIZE; i++)
        page_fault(11,i);
    alloc_pt(MAX_PT_SIZE,1);
    for(i=0;i<MAX_PT_SIZE; i++)
        page_fault(12,i);
    alloc_pt(MAX_PT_SIZE,2);
    for(i=0;i<MAX_PT_SIZE; i++)
        page_fault(13,i);
    alloc_pt(MAX_PT_SIZE,2);
    for(i=0;i<MAX_PT_SIZE; i++)
        page_fault(14,i);
    alloc_pt(MAX_PT_SIZE,2);
    for(i=0;i<MAX_PT_SIZE; i++)
        page_fault(15,i);
    alloc_pt(MAX_PT_SIZE,2);
    for(i=0;i<MAX_PT_SIZE; i++)
        page_fault(16,i);
    

    sizePM = getSize(1);
    sizeBS = getSize(2);
    temp=0;
    if(sizePM == 256)
        temp++;
    if(sizePM > 0)
        temp++;
    dealloc_pt(1);
    dealloc_pt(2);
    dealloc_pt(3);
    dealloc_pt(4);
    dealloc_pt(5);
    dealloc_pt(6);
    dealloc_pt(7);
    dealloc_pt(8);
    dealloc_pt(9);
    dealloc_pt(10);
    dealloc_pt(11);
    sizePM = getSize(1);
    sizeBS = getSize(2);
    
    if(sizePM < 256)
        temp++;
    if(sizePM > 0)
        temp++;
    if(temp == 4)
        printf("Max of Physical Memory/Overflow into Backing Store/Deallocate Some Page Tables: PASSED\n");
    else
        printf("Max of Physical Memory/Overflow into Backing Store/Deallocate Some Page Tables: *FAILED*\n");
    
    /*********************************************
     Max Queues/Clear All Page Tables
     Ensures the queues can be filled to capacity
     with page tables and then delete all the page 
     tables and their memory the to leave the queues empty
    ********************************************/
    printf("\n**Max Queues/Clear All**\n");
    
    clearMemory();
    alloc_pt(MAX_PT_SIZE,2);
    for(i=0;i<MAX_PT_SIZE; i++)
        page_fault(0,i);
    alloc_pt(MAX_PT_SIZE,1);
    for(i=0;i<MAX_PT_SIZE; i++)
        page_fault(1,i);
    alloc_pt(MAX_PT_SIZE,1);
    for(i=0;i<MAX_PT_SIZE; i++)
        page_fault(2,i);
    alloc_pt(MAX_PT_SIZE,1);
    for(i=0;i<MAX_PT_SIZE; i++)
        page_fault(3,i);
    alloc_pt(MAX_PT_SIZE,1);
    for(i=0;i<MAX_PT_SIZE; i++)
        page_fault(4,i);
    alloc_pt(MAX_PT_SIZE,1);
    for(i=0;i<MAX_PT_SIZE; i++)
        page_fault(5,i);
    alloc_pt(MAX_PT_SIZE,1);
    for(i=0;i<MAX_PT_SIZE; i++)
        page_fault(6,i);
    alloc_pt(MAX_PT_SIZE,1);
    for(i=0;i<MAX_PT_SIZE; i++)
        page_fault(7,i);
    alloc_pt(MAX_PT_SIZE,1);
    for(i=0;i<MAX_PT_SIZE; i++)
        page_fault(8,i);
    alloc_pt(MAX_PT_SIZE,1);
    for(i=0;i<MAX_PT_SIZE; i++)
        page_fault(9,i);
    alloc_pt(MAX_PT_SIZE,1);
    for(i=0;i<MAX_PT_SIZE; i++)
        page_fault(10,i);
    alloc_pt(MAX_PT_SIZE,1);
    for(i=0;i<MAX_PT_SIZE; i++)
        page_fault(11,i);
    alloc_pt(MAX_PT_SIZE,1);
    for(i=0;i<MAX_PT_SIZE; i++)
        page_fault(12,i);
    alloc_pt(MAX_PT_SIZE,2);
    for(i=0;i<MAX_PT_SIZE; i++)
        page_fault(13,i);
    alloc_pt(MAX_PT_SIZE,2);
    for(i=0;i<MAX_PT_SIZE; i++)
        page_fault(14,i);
    alloc_pt(MAX_PT_SIZE,2);
    for(i=0;i<MAX_PT_SIZE; i++)
        page_fault(15,i);
    
    sizePM = getSize(1);
    sizeBS = getSize(2);

    temp=0;
    if(sizePM == 256)
        temp++;
    if(sizePM > 0)
        temp++;
    dealloc_pt(0);
    dealloc_pt(1);
    dealloc_pt(2);
    dealloc_pt(3);
    dealloc_pt(4);
    dealloc_pt(5);
    dealloc_pt(6);
    dealloc_pt(7);
    dealloc_pt(8);
    dealloc_pt(9);
    dealloc_pt(10);
    dealloc_pt(11);
    dealloc_pt(12);
    dealloc_pt(13);
    dealloc_pt(14);
    dealloc_pt(15);
    
    sizePM = getSize(1);
    sizeBS = getSize(2);

    if(sizePM == 1)
        temp++;
    if(sizeBS == 0)
        temp++;
    if(temp == 4)
        printf("Max of Physical Memory/Overflow into Backing Store/Deallocate ALL Page Tables: PASSED\n");
    else
        printf("Max of Physical Memory/Overflow into Backing Store/Deallocate ALL Page Tables: *FAILED*\n");
    

    return 0;
}
